package com.opennews.openplatform

import grails.compiler.GrailsCompileStatic
import grails.gorm.transactions.Transactional
import groovy.transform.CompileDynamic
import org.hibernate.criterion.CriteriaSpecification
import org.hibernate.sql.JoinType

@Transactional(readOnly = true)
@GrailsCompileStatic
class AccountGroupUserService {
    UserService userService
    UserActiveTokenService userActiveTokenService

    @CompileDynamic
    List<Map<String, ?>> queryAvailableAccountGroups(String userId) {
        def accountGroupIds = AccountGroupUser.where {
            user == User.proxy(userId)
        }.projections {
            property("accountGroup.id")
        }  as List<String>

        return AccountGroupUser.createCriteria().list {
            // Transforms the result data format to Map instance.
            resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)

            // Sets the join type for user property in order to get its properties.
            createAlias("user", "user", JoinType.INNER_JOIN)

            // Sets the query condition.
            and {
                'in'("accountGroup.id", accountGroupIds)
                eq("isAccountGroupCreator", true)
            }

            // Specifies the property we need.
            projections {
                property("user.id", "id")
                property("accountGroup.id", "accountGroupId")
                property("user.username", "username")
                property("user.fullName", "fullName")
                property("user.avatarFilename", "avatarFilename")
            }

            order("user.fullName", "asc")
        }.collect {Map<String, ?> it -> [
            id: it.accountGroupId,
            isOwner: it.id == userId,
            ownerId: it.id,
            ownerUsername: it.username,
            ownerFullName: it.fullName,
            ownerAvatarUrl: userService.getAvatarUrl(it.avatarFilename)
        ]} as List<Map<String, ?>>
    }

    @Transactional
    @CompileDynamic
    void remove(String accountGroupId, String userId, String username) {
        // Removes user from this account group.
        AccountGroupUser.where {
            accountGroup == AccountGroup.proxy(accountGroupId) &&
                user == User.proxy(userId) &&
                isAccountGroupCreator == false
        }.deleteAll()

        // Removes user roles in this account group.
        UserRole.where {
            accountGroup == AccountGroup.proxy(accountGroupId) &&
                user == User.proxy(userId)
        }.deleteAll()

        // Checks if this is user's default account group.
        if (User.countByIdAndAccountGroup(userId, AccountGroup.proxy(accountGroupId)) > 0) {
            // Sets user's own account group as default.
            userService.restoreAccountGroupByUserId(userId)

            // Deletes all tokens related to this account group to force a re-login.
            userActiveTokenService.deleteByUserAndAccountGroup(username, accountGroupId)
        }
    }
}